package ntd.util.modular.data.util.handle;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.cron.CronUtil;
import cn.hutool.cron.task.Task;
import cn.hutool.extra.spring.SpringUtil;
import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import cn.hutool.http.HttpUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import cn.hutool.log.StaticLog;
import ntd.block.server.bo.ComServerHttpMsgBo;
import ntd.block.server.bo.ComServerMsgBo;
import ntd.block.server.listen.ComAbsServerListen;
import ntd.util.config.common.enums.data.EnumDataAcquisitionType;
import ntd.util.config.common.enums.data.EnumProtocolType;
import ntd.util.frame.server.ServerManager;
import ntd.util.frame.server.util.UtilServer;
import ntd.util.modular.data.entity.DataAcquisitionRecords;
import ntd.util.modular.data.entity.DataAcquisitionRule;
import ntd.util.modular.data.service.DataAcquisitionRecordsService;
import ntd.util.modular.data.util.handle.bo.ComRuleConfigBo;
import ntd.util.modular.data.util.handle.context.ContextDataRuleExecute;
import com.c.Constant;
import ntd.util.util.UtilStrTemplate;
import org.springframework.stereotype.Component;

import javax.annotation.PostConstruct;
import java.util.Map;

@Component
public class ComDataGetRuleHttp implements ComDataGetRule {

    private static DataAcquisitionRecordsService dataAcquisitionRecordsService;

    private static ServerManager serverManager;

    @PostConstruct
    public void init() {
        dataAcquisitionRecordsService = SpringUtil.getBean(DataAcquisitionRecordsService.class);
        serverManager = SpringUtil.getBean(ServerManager.class);
    }

    private ContextDataRuleExecute contextDataRuleExecute;

    private String scheduleId;

    @Override
    public Object handle(DataAcquisitionRule dataAcquisitionRule) {
        if (!dataAcquisitionRule.getEnumProtocolType().equals(EnumProtocolType.HTTP)) {
            return "非HTTP协议，不能执行该模块！";
        }

        if (dataAcquisitionRule.getEnumDataAcquisitionType().equals(EnumDataAcquisitionType.RULE_ACTIVE)) {
            contextDataRuleExecute = ContextDataRuleExecute.init(dataAcquisitionRule);

            String extendJson = dataAcquisitionRule.getExtendJson();

            if (StrUtil.isBlank(extendJson) || !JSONUtil.isJsonObj(extendJson)) {
                return "扩展数据异常【空或者非json格式】！";
            }

            scheduleId = CronUtil.schedule(contextDataRuleExecute.getCron(), (Task) () -> {
                execute(BeanUtil.copyProperties(this.contextDataRuleExecute, ContextDataRuleExecute.class));
            });
        }

        if (dataAcquisitionRule.getEnumDataAcquisitionType().equals(EnumDataAcquisitionType.RULE_PASSIVE)) {
            ComRuleConfigBo comRuleConfigBo = ComRuleConfigBo.transform(dataAcquisitionRule.getExtendJson());

            UtilServer.addListen(comRuleConfigBo.getServerAppId(), new ComAbsServerListen(){
                @Override
                public ComServerMsgBo onMsg(ComServerMsgBo comServerMsgBo) {
                    ComServerHttpMsgBo comServerHttpMsgBo = JSONUtil.toBean(comServerMsgBo.getMsg(), ComServerHttpMsgBo.class);
                    if (comRuleConfigBo.getHttpPath().equals(comServerMsgBo.getKey())) {
                        comServerMsgBo.setMsg(callBack(dataAcquisitionRule, comServerHttpMsgBo.getMergeParams().toString()));
                        return comServerMsgBo;
                    }
                    return null;
                }
            });
        }

        return "规则执行成功";
    }

    private String callBack(DataAcquisitionRule dataAcquisitionRule, String data) {
        DataAcquisitionRecords dataAcquisitionRecords = new DataAcquisitionRecords();
        dataAcquisitionRecords.setDataAcquisitionRuleId(dataAcquisitionRule.getId());
        dataAcquisitionRecords.setTenantId(dataAcquisitionRule.getTenantId());
        dataAcquisitionRecords.setContent(data);
        dataAcquisitionRecordsService.saveOrUpdate(dataAcquisitionRecords);
        return null;
    }

    public void execute(ContextDataRuleExecute contextDataRuleExecute) {
        String logicParams = contextDataRuleExecute.getLogicParams();
        String originPath = contextDataRuleExecute.getPath();
        String params = contextDataRuleExecute.getParams();
        if (JSONUtil.isJsonArray(logicParams)) {
            JSONArray jsonArray = JSONUtil.parseArray(logicParams);
            for (int i = 0; i < jsonArray.size(); i++) {
                contextDataRuleExecute.setPath(UtilStrTemplate.replaceTemplate(originPath, jsonArray.getStr(i)));
                contextDataRuleExecute.setParams(UtilStrTemplate.replaceTemplate(params, jsonArray.getStr(i)));
                executeItem(contextDataRuleExecute);
            }
            return;
        }
        if (JSONUtil.isJsonObj(logicParams)) {
            contextDataRuleExecute.setPath(UtilStrTemplate.replaceTemplate(originPath, logicParams));
            contextDataRuleExecute.setParams(UtilStrTemplate.replaceTemplate(params, logicParams));
            executeItem(contextDataRuleExecute);
            return;
        }
        executeItem(contextDataRuleExecute);
    }

    private void executeItem(ContextDataRuleExecute contextDataRuleExecute) {
        DataAcquisitionRule dataAcquisitionRule = contextDataRuleExecute.getDataAcquisitionRule();
        String httpParams = contextDataRuleExecute.getParams();
        String path = contextDataRuleExecute.getPath();

        JSONObject httpParamsObj = JSONUtil.parseObj(ObjectUtil.defaultIfBlank(httpParams, Constant.JSON_OBJECT_DEFAULT));

        if (StrUtil.isBlank(contextDataRuleExecute.getPort())) {
            EnumProtocolType enumProtocolType = contextDataRuleExecute.getEnumProtocolType();
            contextDataRuleExecute.setPort(enumProtocolType.equals(EnumProtocolType.HTTP) ? "80" : "443");
        }

        String url = contextDataRuleExecute.getHost() + ":" + contextDataRuleExecute.getPort() + path;

        StaticLog.info("发起请求 - " + url);
        HttpRequest request = HttpUtil.createRequest(contextDataRuleExecute.getMethod(), url);

        if (StrUtil.equals(contextDataRuleExecute.getDataType(), "json")) {
            request.body(httpParams);
        }
        if (StrUtil.equals(contextDataRuleExecute.getDataType(), "form") || StrUtil.equals(contextDataRuleExecute.getDataType(), "url")) {
            request.form(httpParamsObj);
        }
        String headers = contextDataRuleExecute.getHeaders();
        if (StrUtil.isNotBlank(headers) && JSONUtil.isJson(headers)) {
            JSONObject jsonObject = JSONUtil.parseObj(headers);
            for (Map.Entry<String, Object> stringObjectEntry : jsonObject.entrySet()) {
                request.header(stringObjectEntry.getKey(), String.valueOf(stringObjectEntry.getValue()));
            }
        }
        try {
            HttpResponse execute = request.execute();
            saveData(dataAcquisitionRule, httpParams, url, headers, execute.body());
        } catch (Exception e) {
            StaticLog.error(e, "[数据采集][http主动请求][{}]失败...", url);
            StaticLog.info("规则[{}]执行失败", dataAcquisitionRule.getId());
        }
    }

    private void saveData(DataAcquisitionRule dataAcquisitionRule, String httpParams, String url, String headers, String data) {
        DataAcquisitionRecords dataAcquisitionRecords = new DataAcquisitionRecords();
        dataAcquisitionRecords.setDataAcquisitionRuleId(dataAcquisitionRule.getId());
        dataAcquisitionRecords.setTenantId(dataAcquisitionRule.getTenantId());
        dataAcquisitionRecords.setRequestHeader(headers);
        dataAcquisitionRecords.setRequestParams(httpParams);
        dataAcquisitionRecords.setRequestUrl(url);
        dataAcquisitionRecords.setContent(data);
        dataAcquisitionRecordsService.saveOrUpdate(dataAcquisitionRecords);
    }

    @Override
    public void close() {
        CronUtil.remove(scheduleId);
    }

}
